/**
 * Licensed under the Apache License, Version 2.0 http://www.apache.org/licenses/LICENSE-2.0
 * @brief FreeRTOS应用示例
 * @details
 * @author 王炸物联网https://blog.csdn.net/wangyx1234?spm=1000.2115.3001.5343
 * @date 2022
 * @version 1.0
 * @copyright 版权所有，禁止用于商业用途
 */
#include <stdio.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

#include "esp_system.h"
#include "esp_spi_flash.h"
#include "esp_log.h"

TaskHandle_t task1; // 任务1结构对象
TaskHandle_t task2;
TaskHandle_t task3;
TaskHandle_t task4;

static int task1_flag;           // 用于指示任务运行状态的标志变量
static int task2_flag;           
static int task3_flag;           

static int tasks_info(char **argv)
{
    const size_t bytes_per_task = 40; /* see vTaskList description */
    char *task_list_buffer = malloc(uxTaskGetNumberOfTasks() * bytes_per_task);
    if (task_list_buffer == NULL) {
        printf("failed to allocate buffer for vTaskList output\r\n");
        return -1;
    }
    fputs("Task Name\tStatus\tPrio\tHWM\tTask#", stdout);
#ifdef CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID
    fputs("\tAffinity", stdout);
#endif
    fputs("\n", stdout);
    vTaskList(task_list_buffer);
    fputs(task_list_buffer, stdout);
    free(task_list_buffer);
    return 0;
}

/**
 * 任务的运行代码
 * @param param 任务初始运行参数
 */
static void task1_process(void *arg)
{
    static const char *TASK1_TAG = "TASK1";
    while (1) {
        task1_flag++;
        vTaskDelay(pdMS_TO_TICKS(1000));
    }
}

static void task2_process(void *arg)
{
    static const char *TASK2_TAG = "TASK2";
    while (1) {
        ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
        task2_flag++;
        vTaskDelay(pdMS_TO_TICKS(2000));
    }
}

static void task3_process(void *arg)
{
    static const char *TASK3_TAG = "TASK3";
    while (1) {
        printf("%s: task3_flag = %d\r\n", TASK3_TAG, task3_flag);
        task3_flag++;


        if(task3_flag == 3) {
            vTaskResume(task1);
            xTaskNotifyGive(task2);
        }

        vTaskDelay(pdMS_TO_TICKS(2500));
    }
}

static void task4_process(void *arg)
{
    while (1) {
        for(int i=0; i<12; i++) {
            tasks_info(NULL);
            vTaskDelay(pdMS_TO_TICKS(1000));
        }
    }
}

static void init(void) {
    printf("Hello world!\n");

    /* Print chip information */
    esp_chip_info_t chip_info;
    esp_chip_info(&chip_info);
    printf("This is %s chip with %d CPU core(s), WiFi%s%s, ",
            CONFIG_IDF_TARGET,
            chip_info.cores,
            (chip_info.features & CHIP_FEATURE_BT) ? "/BT" : "",
            (chip_info.features & CHIP_FEATURE_BLE) ? "/BLE" : "");

    printf("Minimum free heap size: %d bytes\n", esp_get_minimum_free_heap_size());
}

void app_main(void)
{
    init();
    /*
    static BaseType_t xTaskCreate(TaskFunction_t pvTaskCode, const char *constpcName, const uint32_t usStackDepth, 
    void *constpvParameters, UBaseType_t uxPriority, TaskHandle_t *constpxCreatedTask)*/
    xTaskCreate(&task1_process, "task1", 1024*2, (void *)"1", configMAX_PRIORITIES-1, &task1); // configMAX_PRIORITIES = 25
    xTaskCreate(&task2_process, "task2", 1024*2, (void *)"2", configMAX_PRIORITIES-2, &task2);
    xTaskCreate(&task3_process, "task3", 1024*2, (void *)"3", configMAX_PRIORITIES-3, &task3);
    xTaskCreate(&task4_process, "task4", 1024*2, (void *)"4", configMAX_PRIORITIES, &task4);
    vTaskSuspend(task1);
    vTaskSuspend(task4);

    TaskStatus_t pxTaskStatus;
     // To obtain further information about the task.
    vTaskGetInfo(NULL, // Task handle, use NULL to current task.
                &pxTaskStatus,
                pdTRUE, // Include the high water mark in xTaskDetails.
                eInvalid); // Include the task state in xTaskDetails.
    printf("\r\napp_main task status: xTaskNumber=%d eCurrentState=%d uxCurrentPriority=%d\r\n", pxTaskStatus.xTaskNumber, pxTaskStatus.eCurrentState, pxTaskStatus.uxCurrentPriority);
    vTaskResume(task4);
}
